; 文件名: boot.s
; 编译命令: nasm mbr.s -f bin -o mbr.bin
; https://yanfukun.com/read/myos/hdio

;---------- loader 和 kernel ------------
LOADER_BASE_ADDER 			equ 0x7e00   ;内存首址
BOOT_LOADER_STAER_SECTOR 	equ 0x2     ;硬盘扇区
BOOT_LOADER_SECTOR_SIZE 	equ 0x1		;

bits 16         ; 16位实模式
[org 0x7C00]      ; BIOS 加载MBR到内存地址0x7C00



;初始化boot运行环境 
;---------------------------------------------------------------------------------------
;  cs = 0x7c00	gs = 0xb800 ss = 0x9000	sp = 0x9fbff
;---------------------------------------------------------------------------------------
;  sp 指向实模式下的可用空间的最末尾
;  无返回值
init_boot_env:
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov fs,ax
	mov ax,0x9000
	mov ss,ax
    mov sp,0xfbff
    mov ax,0xb800
    mov gs,ax

	call clear_bios_screen_buffer

	jmp boot_program_start


;清屏 
;利用0x06号功能，上卷全部行，则可清屏
;---------------------------------------------------------------------------------------
;  INT 0x10   功能号：0x06  功能描述： 上卷窗口
;---------------------------------------------------------------------------------------
;  输入：
;  AH 功能号= 0x06
;  AL = 上卷的行数(若为0,表示全部)
;  BH = 上卷行属性
;  (CL,CH) = 窗口左上角的(X,Y)位置
;  (DL,DH) = 窗口右下角的(X,Y)位置
;  无返回值
;
clear_bios_screen_buffer:
	pusha
    mov ax,0600h
    mov bx,0700h
    mov cx,0          ; 左上角：(0,0)
    mov dx,184fh      ; 右下角：(80,25)
                  	  ; VGA文本模式中，一行只能容纳80个字符，共25行
                  	  ; 下标0开始，所以0x18=24，0x4f=79
    int 10h      	  ; int 0x10
	popa
	ret


;boot 启动
;---------------------------------------------------------------------------------------
;  init_boot_env   调用清理屏幕函数
;---------------------------------------------------------------------------------------
;  执行完清理屏幕的函数后
;  立即返回到  boot_program_start
;
start:
	jmp init_boot_env


;boot真正的boot开始函数
;---------------------------------------------------------------------------------------
;	IO PORT 0x1F6   0x1F2
;---------------------------------------------------------------------------------------
;	0x1F6:
;	0-3：LBA地址高4位
;	4:表示选择主驱动器,1表示选择从驱动器
;	5:必须为1
;	6:必须为1表示Lba,0表示CHS
;	7:必须为1
; 	0x1F7:0x20 read 0x30 write
;	
boot_program_start:
    ; 设置读取的扇区数
	pusha

	mov si,0x0
	mov di,LOADER_BASE_ADDER

    mov dx, 0x1F2
    mov al, BOOT_LOADER_SECTOR_SIZE           ; 读取1个扇区
    out dx, al
    ; 设置要读取的扇区号（LBA地址）
    mov dx, 0x1F3
    mov al, 1           ; LBA 地址低8位（第1扇区）
    out dx, al
    ; 设置柱面号（LBA地址的8-23位）
    mov dx, 0x1F4
    mov al, 0           ; LBA 地址的8-15位
    out dx, al
    mov dx, 0x1F5
    mov al, 0           ; LBA 地址的16-23位
    out dx, al
    ; 设置驱动器和LBA的高4位
    mov dx, 0x1F6
    mov al, 0xE0        ; 主驱动器，LBA 地址的24-27位(0xE0 = 1110 0000)
    out dx, al
    ; 发送读命令
    mov dx, 0x1F7
    mov al, 0x20        ; 0x20 是读取命令
    out dx, al
    ; 等待磁盘准备就绪
    .wait_ready:
        in al, dx
        test al, 0x80   ; 检查 BSY 位（位7）
        jnz .wait_ready
    ; 读取数据
    mov dx, 0x1F0       ; 数据端口
    mov cx, 256         ; 每个扇区512字节 / 2 = 256次读取
    rep insw            ; 从端口读取数据到内存

	popa

	; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
	mov byte [gs:0x00],'2'
	mov byte [gs:0x01],0xA4 ; A 表示绿色背景闪烁， 4 表示前景色为红色

	mov byte [gs:0x02],' '
	mov byte [gs:0x03],0xA4

	mov byte [gs:0x04],'L'
	mov byte [gs:0x05],0xA4

	mov byte [gs:0x06],'O'
	mov byte [gs:0x07],0xA4

	mov byte [gs:0x08],'A'
	mov byte [gs:0x09],0xA4

	mov byte [gs:0x0a],'D'
	mov byte [gs:0x0b],0xA4

	mov byte [gs:0x0c],'E'
	mov byte [gs:0x0d],0xA4

	mov byte [gs:0x0e],'R'
	mov byte [gs:0x0f],0xA4

	jmp $ ; 通过死循环使程序悬停在此


; 填充剩余空间并添加MBR签名
times 510 - ($ - $$) db 0   ; 填充510字节
dw 0xAA55                   ; MBR结束标志 (小端存储)